<?php
namespace app\admin\controller\plugin;
use app\common\annotation\NodeAnnotation;
use app\common\controller\Admin;
use app\common\traits\ControllerCurd;
use think\facade\Validate;
use think\Request;
/**
 * @package app\admin\controller\system
 * @NodeAnnotation(
 *     title="插件中心",
 *     is_menu=1,
 *     is_view=0,
 *     icon="/material/plugin.png"
 * )
 */
class Plugin extends Admin
{
    use ControllerCurd;
    public $model;
    public function initialize()
    {
        parent::initialize();
        $this->model= new \app\admin\model\plugin\Plugin();
    }

    /**
     * @NodeAnnotation(
     *     title="插件列表",
     *     parent="admin/plugin.plugin",
     *     MenuRoot="admin/plugin.plugin"
     * )
     */
    public function index(Request $request)
    {
        $pluginModel = new \app\admin\model\plugin\Plugin();
        $plugins     = $pluginModel->getList();
        $this->assign("plugins", $plugins);
        return $this->fetch();
    }
    /**
     * @NodeAnnotation(
     *     title="插件安装",
     *     parent="admin/plugin.plugin",
     *     MenuRoot="admin/plugin.plugin",
     *     is_menu = 0,
     *     is_view = 0
     * )
     */
    public function install()
    {
        $pluginName = $this->request->param('name', '', 'trim');
        $class      = get_plugin_class($pluginName);
        if (!class_exists($class))
        {
            $this->error('插件不存在!');
        }

        $pluginCount = $this->model->where('name', $pluginName)->count();

        if ($pluginCount > 0)
        {
            $this->error('插件已安装!');
        }

        $plugin = new $class;
        $info   = $plugin->info;
        //检测信息的正确性
        if (!$info || !$plugin->checkInfo())
        {
            $this->error('插件信息缺失!');
        }

        $installSuccess = $plugin->install();
        if (!$installSuccess) {
            $this->error('插件预安装失败!');
        }

        $methods = get_class_methods($plugin);
        foreach ($methods as $methodKey => $method) {
            $methods[$methodKey] = parse_name($method);
        }

        //钩子处理
        /*$systemHooks = $this->model->getHooks(true);

        $pluginHooks = array_intersect($systemHooks, $methods);*/

        //$info['hooks'] = implode(",", $pluginHooks);

        if (!empty($plugin->hasAdmin))
        {
            $info['has_admin'] = 1;
        } else {
            $info['has_admin'] = 0;
        }

        $info['config'] = json_encode($plugin->getConfigs());

        $this->model->data($info)->allowField(true)->save();

        //添加钩子
       /* $hookPluginModel = new HookPluginModel();
        foreach ($pluginHooks as $pluginHook) {
            $hookPluginModel->data(['hook' => $pluginHook, 'plugin' => $pluginName, 'status' => 1])->isUpdate(false)->save();
        }*/

       //插件菜单
        //$this->_getActions($pluginName);

        //Cache::clear('init_hook_plugins');
        //Cache::clear('admin_menus');

        $this->success('安装成功!');
    }
    /**
     * @NodeAnnotation(
     *     title="插件卸载",
     *     parent="admin/plugin.plugin",
     *     MenuRoot="admin/plugin.plugin",
     *     is_menu = 0,
     *     is_view = 0
     * )
     */
    public function uninstall()
    {
        $id          = $this->request->param('id', 0, 'intval');
        $result = $this->model->uninstall($id);

        if ($result !== true) {
            $this->error('卸载失败!');
        }

        //Cache::clear('init_hook_plugins');
        //Cache::clear('admin_menus');// 删除后台菜单缓存

        $this->success('卸载成功!');
    }
    /**
     * @NodeAnnotation(
     *     title="插件更新",
     *     parent="admin/plugin.plugin",
     *     MenuRoot="admin/plugin.plugin",
     *     is_menu = 0,
     *     is_view = 0
     * )
     */
    public function update()
    {
        $pluginName = $this->request->param('name', '', 'trim');
        $class      = get_plugin_class($pluginName);
        if (!class_exists($class)) {
            $this->error('插件不存在!');
        }

        $plugin = new $class;
        $info   = $plugin->info;
        if (!$info || !$plugin->checkInfo()) {//检测信息的正确性
            $this->error('插件信息缺失!');
        }

        $methods = get_class_methods($plugin);

        foreach ($methods as $methodKey => $method) {
            $methods[$methodKey] = parse_name($method);
        }

        /*$pluginModel = new PluginModel();
        $systemHooks = $pluginModel->getHooks(true);

        $pluginHooks = array_intersect($systemHooks, $methods);*/

        if (!empty($plugin->hasAdmin)) {
            $info['has_admin'] = 1;
        } else {
            $info['has_admin'] = 0;
        }

        $config = $plugin->getConfigs();

        $defaultConfig = $plugin->getDefaultConfig();

        $pluginModel = $this->model;


        $config = array_merge($defaultConfig, $config);

        $info['config'] = json_encode($config);

        $pluginModel->allowField(true)->save($info, ['name' => $pluginName]);

        //$hookPluginModel = new HookPluginModel();

        //$pluginHooksInDb = $hookPluginModel->where('plugin', $pluginName)->column('hook');

        //$samePluginHooks = array_intersect($pluginHooks, $pluginHooksInDb);

        //$shouldDeleteHooks = array_diff($samePluginHooks, $pluginHooksInDb);

        //$newHooks = array_diff($pluginHooks, $samePluginHooks);

        /*if (count($shouldDeleteHooks) > 0) {
            $hookPluginModel->where('hook', 'in', $shouldDeleteHooks)->delete();
        }*/

       /* foreach ($newHooks as $pluginHook) {
            $hookPluginModel->data(['hook' => $pluginHook, 'plugin' => $pluginName])->isUpdate(false)->save();
        }*/

        //$this->_getActions($pluginName);

        /*Cache::clear('init_hook_plugins');
        Cache::clear('admin_menus');// 删除后台菜单缓存*/

        $this->success('更新成功!');
    }
    /**
     * @NodeAnnotation(
     *     title="插件启用禁用",
     *     parent="admin/plugin.plugin",
     *     MenuRoot="admin/plugin.plugin",
     *     is_menu = 0,
     *     is_view = 0
     * )
     */
    public function toggle()
    {
        $id = $this->request->param('id', 0, 'intval');

        $pluginModel = $this->model->find($id);

        if (empty($pluginModel)) {
            $this->error('插件不存在！');
        }

        $status         = 1;
        $successMessage = "启用成功！";

        if ($this->request->param('disable')) {
            $status         = 0;
            $successMessage = "禁用成功！";
        }

        $pluginModel->startTrans();

        try {
            $pluginModel->save(['status' => $status], ['id' => $id]);

            /*$hookPluginModel = new HookPluginModel();

            $hookPluginModel->save(['status' => $status], ['plugin' => $pluginModel->name]);*/

            $pluginModel->commit();

        } catch (\Exception $e) {

            $pluginModel->rollback();

            $this->error('操作失败！');
        }
        //Cache::clear('init_hook_plugins');

        $this->success($successMessage);
    }
    /**
     * @NodeAnnotation(
     *     title="插件设置",
     *     parent="admin/plugin.plugin",
     *     MenuRoot="admin/plugin.plugin",
     *     is_menu = 0,
     *     is_view = 1
     * )
     */
    public function setting()
    {
        $id = $this->request->param('id', 0, 'intval');

        $pluginModel = $this->model;
        $plugin      = $pluginModel->find($id);

        if (empty($plugin)) {
            $this->error('插件未安装!');
        }

        $plugin = $plugin->toArray();

        $pluginClass = get_plugin_class($plugin['name']);
        if (!class_exists($pluginClass)) {
            $this->error('插件不存在!');
        }

        $pluginObj = new $pluginClass;
        //$plugin['plugin_path']   = $pluginObj->plugin_path;
        //$plugin['custom_config'] = $pluginObj->custom_config;
        $pluginConfigInDb = $plugin['config'];
        $plugin['config'] = include $pluginObj->getConfigFilePath();

        if ($pluginConfigInDb) {
            $pluginConfigInDb = json_decode($pluginConfigInDb, true);
            foreach ($plugin['config'] as $key => $value) {
                if ($value['type'] != 'group') {
                    if (isset($pluginConfigInDb[$key])) {
                        $plugin['config'][$key]['value'] = $pluginConfigInDb[$key];
                    }
                } else {
                    foreach ($value['options'] as $group => $options) {
                        foreach ($options['options'] as $gkey => $value) {
                            if (isset($pluginConfigInDb[$gkey])) {
                                $plugin['config'][$key]['options'][$group]['options'][$gkey]['value'] = $pluginConfigInDb[$gkey];
                            }
                        }
                    }
                }
            }
        }

        $this->assign('data', $plugin);
//        if ($plugin['custom_config']) {
//            $this->assign('custom_config', $this->fetch($plugin['plugin_path'] . $plugin['custom_config']));
//        }
        $this->assign('id', $id);
        return $this->fetch();

    }

    /**
     * @NodeAnnotation(
     *     title="插件设置提交",
     *     parent="admin/plugin.plugin",
     *     MenuRoot="admin/plugin.plugin",
     *     is_menu = 0,
     *     is_view = 0
     * )
     */
    public function settingPost()
    {
        if ($this->request->isPost()) {
            $id = $this->request->param('id', 0, 'intval');

            $pluginModel = $this->model;
            $plugin      = $pluginModel->find($id);

            if (!$plugin) {
                $this->error('插件未安装!');
            }

            $pluginClass = get_plugin_class($plugin['name']);
            if (!class_exists($pluginClass)) {
                $this->error('插件不存在!');
            }

            $pluginObj = new $pluginClass;
            //$plugin['plugin_path']   = $pluginObj->plugin_path;
            //$plugin['custom_config'] = $pluginObj->custom_config;
            $pluginConfigInDb = $plugin['config'];
            $plugin['config'] = include $pluginObj->getConfigFilePath();

            $rules    = [];
            $messages = [];

            foreach ($plugin['config'] as $key => $value) {
                if ($value['type'] != 'group') {
                    if (isset($value['rule'])) {
                        $rules[$key] = $this->_parseRules($value['rule']);
                    }

                    if (isset($value['message'])) {
                        foreach ($value['message'] as $rule => $msg) {
                            $messages[$key . '.' . $rule] = $msg;
                        }
                    }

                } else {
                    foreach ($value['options'] as $group => $options) {
                        foreach ($options['options'] as $gkey => $value) {
                            if (isset($value['rule'])) {
                                $rules[$gkey] = $this->_parseRules($value['rule']);
                            }

                            if (isset($value['message'])) {
                                foreach ($value['message'] as $rule => $msg) {
                                    $messages[$gkey . '.' . $rule] = $msg;
                                }
                            }
                        }
                    }
                }
            }

            $config = $this->request->param('config');

            $validate = new \think\Validate($rules, $messages);
            $result   = $validate->check($config);
            if ($result !== true) {
                $this->error($validate->getError());
            }

            $pluginModel = $this->model;
            $pluginModel->save(['config' => json_encode($config)], ['id' => $id]);
            $this->success('保存成功', '');
        }
    }

    /**
     * 解析插件配置验证规则
     * @param $rules
     */
    private function _parseRules($rules)
    {
        $newRules = [];

        $simpleRules = [
            'require', 'number',
            'integer', 'float', 'boolean', 'email',
            'array', 'accepted', 'date', 'alpha',
            'alphaNum', 'alphaDash', 'activeUrl',
            'url', 'ip'];
        foreach ($rules as $key => $rule) {
            if (in_array($key, $simpleRules) && $rule) {
                array_push($newRules, $key);
            }
        }
        return $newRules;
    }

}